41bf1717bML6GxpclTWJabiaO5W5vg xen/include/asm-x86/x86_64/asm_defns.h
404f1b9ceJeGVaPNIENm2FkK0AgEOQ xen/include/asm-x86/x86_64/current.h
41febc4b1aCGLsm0Y0b_82h7lFtrEA xen/include/asm-x86/x86_64/domain_page.h
-404f1badfXZJZ2sU8sh9PS2EZvd19Q xen/include/asm-x86/x86_64/ldt.h
4208e2a3Fktw4ZttKdDxbhvTQ6brfQ xen/include/asm-x86/x86_64/page.h
404f1bb86rAXB3aLS1vYdcqpJiEcyg xen/include/asm-x86/x86_64/regs.h
40e1966azOJZfNI6Ilthe6Q-T3Hewg xen/include/asm-x86/x86_64/string.h
gdt_segs[GDATA_SEL].ssd_limit = atop(0 - ((1 << 26) - (1 << 22) + (1 << 16)));
#endif
#ifdef SMP
- /* XXX this will blow up if there are more than 512/NGDT vcpus - will never
- * be an issue in the real world but should add an assert on general principles
- * we'll likely blow up when we hit LAST_RESERVED_GDT_ENTRY, at which point we
- * would need to start allocating more pages for the GDT
- */
+ /* XXX this will blow up if there are more than 512/NGDT vcpus */
pc = &SMP_prvspace[0].pcpu;
for (i = 0; i < ncpus; i++) {
cpu_add(i, (i == 0));
PT_SET_MA(gdt, *vtopte((unsigned long)gdt) & ~PG_RW);
gdtmachpfn = vtomach(gdt) >> PAGE_SHIFT;
- PANIC_IF(HYPERVISOR_set_gdt(&gdtmachpfn, LAST_RESERVED_GDT_ENTRY + 1) != 0);
+ PANIC_IF(HYPERVISOR_set_gdt(&gdtmachpfn, 512) != 0);
lgdt_finish();
myid = bootAP;
gdtmachpfn = vtomach(gdt) >> PAGE_SHIFT;
- PANIC_IF(HYPERVISOR_set_gdt(&gdtmachpfn, LAST_RESERVED_GDT_ENTRY + 1) != 0);
+ PANIC_IF(HYPERVISOR_set_gdt(&gdtmachpfn, 512) != 0);
lgdt_finish();
cpu_gdt_descr[cpu].size = cpu_gdt_descr[0].size;
memcpy((void *)cpu_gdt_descr[cpu].address,
(void *)cpu_gdt_descr[0].address, cpu_gdt_descr[0].size);
- memset((char *)cpu_gdt_descr[cpu].address +
- FIRST_RESERVED_GDT_ENTRY * 8, 0,
- NR_RESERVED_GDT_ENTRIES * 8);
memset(&ctxt, 0, sizeof(ctxt));
#define GDT_ENTRY_DOUBLEFAULT_TSS 31
/*
- * The GDT has LAST_RESERVED_GDT_ENTRY + 1 entries
+ * The GDT has 32 entries
*/
-#define GDT_ENTRIES (LAST_RESERVED_GDT_ENTRY + 1)
+#define GDT_ENTRIES 32
#define GDT_SIZE (GDT_ENTRIES * 8)
#define FS_TLS_SEL ((GDT_ENTRY_TLS_MIN+FS_TLS)*8 + 3)
#define IDT_ENTRIES 256
-#define GDT_ENTRIES (LAST_RESERVED_GDT_ENTRY + 1)
+#define GDT_ENTRIES 16
#define GDT_SIZE (GDT_ENTRIES * 8)
#define TLS_SIZE (GDT_ENTRY_TLS_ENTRIES * 8)
pmap_kenter_pa((vaddr_t)gdt, (uint32_t)gdt - KERNBASE,
VM_PROT_READ);
XENPRINTK(("loading gdt %lx, %d entries\n", frames[0] << PAGE_SHIFT,
- LAST_RESERVED_GDT_ENTRY + 1));
- if (HYPERVISOR_set_gdt(frames, LAST_RESERVED_GDT_ENTRY + 1))
+ NGDT);
+ if (HYPERVISOR_set_gdt(frames, NGDT))
panic("HYPERVISOR_set_gdt failed!\n");
lgdt_finish();
#endif
ctxt.gdt_frames[i] = pfn_to_mfn_table[pfn];
}
- /* Zero hypervisor GDT entries (supresses ugly warning) */
- p_gdt = xc_map_foreign_range(
- xc_handle, dom, PAGE_SIZE, PROT_WRITE, ctxt.gdt_frames[0]);
- memset( p_gdt + FIRST_RESERVED_GDT_ENTRY*8, 0,
- NR_RESERVED_GDT_ENTRIES*8 );
- munmap( p_gdt, PAGE_SIZE );
-
/* Uncanonicalise the page table base pointer. */
pfn = ctxt.pt_base >> PAGE_SHIFT;
if ( (pfn >= nr_pfns) || ((pfn_type[pfn]<ABTYPE_MASK) != L2TAB) )
#include <xen/config.h>
#include <public/xen.h>
+#include <asm/desc.h>
#include <asm/page.h>
#define SECONDARY_CPU_FLAG 0xA5A5A5A5
.word 0
idt_descr:
- .word 256*8-1
+ .word 256*8-1
idt:
.long idt_table
.word 0
gdt_descr:
- .word (LAST_RESERVED_GDT_ENTRY*8)+7
-gdt:
- .long gdt_table /* gdt base */
+ .word LAST_RESERVED_GDT_BYTE
+gdt:
+ .long gdt_table - FIRST_RESERVED_GDT_BYTE
.word 0
nopaging_gdt_descr:
- .word (LAST_RESERVED_GDT_ENTRY*8)+7
- .long gdt_table-__PAGE_OFFSET
+ .word LAST_RESERVED_GDT_BYTE
+ .long gdt_table - FIRST_RESERVED_GDT_BYTE - __PAGE_OFFSET
- ALIGN
+ .org 0x1000
/* NB. Rings != 0 get access up to 0xFC400000. This allows access to the */
/* machine->physical mapping table. Ring 0 can access all memory. */
ENTRY(gdt_table)
- .fill FIRST_RESERVED_GDT_ENTRY,8,0
.quad 0x0000000000000000 /* unused */
- .quad 0x00cf9a000000ffff /* 0x0808 ring 0 4.00GB code at 0x0 */
- .quad 0x00cf92000000ffff /* 0x0810 ring 0 4.00GB data at 0x0 */
- .quad 0x00cfba000000c3ff /* 0x0819 ring 1 3.95GB code at 0x0 */
- .quad 0x00cfb2000000c3ff /* 0x0821 ring 1 3.95GB data at 0x0 */
- .quad 0x00cffa000000c3ff /* 0x082b ring 3 3.95GB code at 0x0 */
- .quad 0x00cff2000000c3ff /* 0x0833 ring 3 3.95GB data at 0x0 */
+ .quad 0x00cf9a000000ffff /* 0xe008 ring 0 4.00GB code at 0x0 */
+ .quad 0x00cf92000000ffff /* 0xe010 ring 0 4.00GB data at 0x0 */
+ .quad 0x00cfba000000c3ff /* 0xe019 ring 1 3.95GB code at 0x0 */
+ .quad 0x00cfb2000000c3ff /* 0xe021 ring 1 3.95GB data at 0x0 */
+ .quad 0x00cffa000000c3ff /* 0xe02b ring 3 3.95GB code at 0x0 */
+ .quad 0x00cff2000000c3ff /* 0xe033 ring 3 3.95GB data at 0x0 */
.quad 0x0000000000000000 /* unused */
.fill 2*NR_CPUS,8,0 /* space for TSS and LDT per CPU */
- .org 0x1000
-ENTRY(idle_pg_table) # Initial page directory is 4kB
.org 0x2000
+ENTRY(idle_pg_table) # Initial page directory is 4kB
+ .org 0x3000
ENTRY(cpu0_stack)
- .org 0x2000 + STACK_SIZE
+ .org 0x3000 + STACK_SIZE
ENTRY(stext)
ENTRY(_stext)
#include <xen/config.h>
#include <public/xen.h>
+#include <asm/desc.h>
#include <asm/page.h>
#include <asm/msr.h>
cli
/* Set up a few descriptors: on entry only CS is guaranteed good. */
- lgdt %cs:0x1001f0
+ lgdt %cs:0x100400
mov $(__HYPERVISOR_DS32),%ecx
mov %ecx,%ds
mov %ecx,%es
jne not_multiboot
/* Save the Multiboot info structure for later use. */
- mov %ebx,0x1001e0
+ mov %ebx,0x100300
/* We begin by interrogating the CPU for the presence of long mode. */
mov $0x80000000,%eax
loop 1b
/* Pass off the Multiboot info structure to C land. */
- mov 0x1001e0,%edi
+ mov 0x100300,%edi
lea start(%rip),%rax
sub $0x100000,%rax
add %rax,%rdi
call __start_xen
ud2 /* Force a panic (invalid opcode). */
+/* This is the default interrupt handler. */
+int_msg:
+ .asciz "Unknown interrupt\n"
+ignore_int:
+ cld
+ leaq int_msg(%rip),%rdi
+ call printf
+1: jmp 1b
+
.code32
- .org 0x1e0
+ .org 0x300
/*** DESCRIPTOR TABLES ***/
.globl idt
-.globl gdt
+.globl gdt
- .org 0x1f0
- .word (LAST_RESERVED_GDT_ENTRY*8)+7
- .long 0x100200 # gdt_table
+ .org 0x400
+ .word LAST_RESERVED_GDT_BYTE
+ .long 0x101000 - FIRST_RESERVED_GDT_BYTE
- .org 0x200
-ENTRY(gdt_table)
- .fill FIRST_RESERVED_GDT_ENTRY,8,0
- .quad 0x0000000000000000 /* unused */
- .quad 0x00cf9a000000ffff /* 0x0808 ring 0 code, compatibility */
- .quad 0x00af9a000000ffff /* 0x0810 ring 0 code, 64-bit mode */
- .quad 0x00cf92000000ffff /* 0x0818 ring 0 data */
- .quad 0x00cffa000000ffff /* 0x0823 ring 3 code, compatibility */
- .quad 0x00cff2000000ffff /* 0x082b ring 3 data */
- .quad 0x00affa000000ffff /* 0x0833 ring 3 code, 64-bit mode */
- .quad 0x0000000000000000 /* unused */
- .fill 4*NR_CPUS,8,0 /* space for TSS and LDT per CPU */
-
.word 0
gdt_descr:
- .word (LAST_RESERVED_GDT_ENTRY*8)+7
+ .word LAST_RESERVED_GDT_BYTE
gdt:
- .quad gdt_table
+ .quad gdt_table - FIRST_RESERVED_GDT_BYTE
.word 0
idt_descr:
high_start:
.quad __high_start
+ .org 0x1000
+ENTRY(gdt_table)
+ .quad 0x0000000000000000 /* unused */
+ .quad 0x00cf9a000000ffff /* 0xe008 ring 0 code, compatibility */
+ .quad 0x00af9a000000ffff /* 0xe010 ring 0 code, 64-bit mode */
+ .quad 0x00cf92000000ffff /* 0xe018 ring 0 data */
+ .quad 0x00cffa000000ffff /* 0xe023 ring 3 code, compatibility */
+ .quad 0x00cff2000000ffff /* 0xe02b ring 3 data */
+ .quad 0x00affa000000ffff /* 0xe033 ring 3 code, 64-bit mode */
+ .quad 0x0000000000000000 /* unused */
+ .fill 4*NR_CPUS,8,0 /* space for TSS and LDT per CPU */
+
/* Initial PML4 -- level-4 page table */
- .org 0x1000
+ .org 0x2000
ENTRY(idle_pg_table)
ENTRY(idle_pg_table_4)
.quad 0x0000000000102007 # PML4[0]
.quad 0x0000000000102007 # PML4[262]
/* Initial PDP -- level-3 page table */
- .org 0x2000
+ .org 0x3000
ENTRY(idle_pg_table_l3)
.quad 0x0000000000103007
/* Initial PDE -- level-2 page table. */
- .org 0x3000
+ .org 0x4000
ENTRY(idle_pg_table_l2)
.macro identmap from=0, count=512
.if \count-1
.endm
identmap /* Too orangey for crows :-) */
- .org 0x4000
+ .org 0x5000
ENTRY(cpu0_stack)
- .org 0x4000 + STACK_SIZE
+ .org 0x5000 + STACK_SIZE
.code64
ENTRY(stext)
ENTRY(_stext)
-
-/* This is the default interrupt handler. */
-int_msg:
- .asciz "Unknown interrupt\n"
-ignore_int:
- cld
- leaq int_msg(%rip),%rdi
- call printf
-1: jmp 1b
-
void arch_getdomaininfo_ctxt(
struct exec_domain *ed, struct vcpu_guest_context *c)
{
- int i;
#ifdef __i386__ /* Remove when x86_64 VMX is implemented */
#ifdef CONFIG_VMX
extern void save_vmx_cpu_user_regs(struct cpu_user_regs *);
c->flags |= VGCF_VMX_GUEST;
#endif
- c->gdt_ents = 0;
- if ( GET_GDT_ADDRESS(ed) == GDT_VIRT_START(ed) )
- {
- for ( i = 0; i < 16; i++ )
- c->gdt_frames[i] =
- l1e_get_pfn(ed->arch.perdomain_ptes[i]);
- c->gdt_ents = GET_GDT_ENTRIES(ed);
- }
-
c->pt_base = pagetable_val(ed->arch.guest_table);
c->vm_assist = ed->domain->vm_assist;
ed->arch.flags = TF_kernel_mode;
- if ( d->domain_id != IDLE_DOMAIN_ID )
- {
- ed->arch.schedule_tail = continue_nonidle_task;
-
- d->shared_info = (void *)alloc_xenheap_page();
- memset(d->shared_info, 0, PAGE_SIZE);
- ed->vcpu_info = &d->shared_info->vcpu_data[ed->vcpu_id];
- ed->cpumap = CPUMAP_RUNANYWHERE;
- SHARE_PFN_WITH_DOMAIN(virt_to_page(d->shared_info), d);
- machine_to_phys_mapping[virt_to_phys(d->shared_info) >>
- PAGE_SHIFT] = INVALID_M2P_ENTRY;
-
- d->arch.mm_perdomain_pt = (l1_pgentry_t *)alloc_xenheap_page();
- memset(d->arch.mm_perdomain_pt, 0, PAGE_SIZE);
- machine_to_phys_mapping[virt_to_phys(d->arch.mm_perdomain_pt) >>
- PAGE_SHIFT] = INVALID_M2P_ENTRY;
- ed->arch.perdomain_ptes = d->arch.mm_perdomain_pt;
+ if ( d->domain_id == IDLE_DOMAIN_ID )
+ return;
- ed->arch.guest_vtable = __linear_l2_table;
- ed->arch.shadow_vtable = __shadow_linear_l2_table;
+ ed->arch.schedule_tail = continue_nonidle_task;
+
+ d->shared_info = (void *)alloc_xenheap_page();
+ memset(d->shared_info, 0, PAGE_SIZE);
+ ed->vcpu_info = &d->shared_info->vcpu_data[ed->vcpu_id];
+ ed->cpumap = CPUMAP_RUNANYWHERE;
+ SHARE_PFN_WITH_DOMAIN(virt_to_page(d->shared_info), d);
+ machine_to_phys_mapping[virt_to_phys(d->shared_info) >>
+ PAGE_SHIFT] = INVALID_M2P_ENTRY;
+
+ d->arch.mm_perdomain_pt = (l1_pgentry_t *)alloc_xenheap_page();
+ memset(d->arch.mm_perdomain_pt, 0, PAGE_SIZE);
+ machine_to_phys_mapping[virt_to_phys(d->arch.mm_perdomain_pt) >>
+ PAGE_SHIFT] = INVALID_M2P_ENTRY;
+ ed->arch.perdomain_ptes = d->arch.mm_perdomain_pt;
+ ed->arch.perdomain_ptes[FIRST_RESERVED_GDT_PAGE] =
+ l1e_create_pfn(page_to_pfn(virt_to_page(gdt_table)),
+ __PAGE_HYPERVISOR);
+
+ ed->arch.guest_vtable = __linear_l2_table;
+ ed->arch.shadow_vtable = __shadow_linear_l2_table;
#ifdef __x86_64__
- ed->arch.guest_vl3table = __linear_l3_table;
- ed->arch.guest_vl4table = __linear_l4_table;
-
- d->arch.mm_perdomain_l2 = (l2_pgentry_t *)alloc_xenheap_page();
- memset(d->arch.mm_perdomain_l2, 0, PAGE_SIZE);
- d->arch.mm_perdomain_l2[l2_table_offset(PERDOMAIN_VIRT_START)] =
- l2e_create_phys(__pa(d->arch.mm_perdomain_pt),
- __PAGE_HYPERVISOR);
- d->arch.mm_perdomain_l3 = (l3_pgentry_t *)alloc_xenheap_page();
- memset(d->arch.mm_perdomain_l3, 0, PAGE_SIZE);
- d->arch.mm_perdomain_l3[l3_table_offset(PERDOMAIN_VIRT_START)] =
- l3e_create_phys(__pa(d->arch.mm_perdomain_l2),
+ ed->arch.guest_vl3table = __linear_l3_table;
+ ed->arch.guest_vl4table = __linear_l4_table;
+
+ d->arch.mm_perdomain_l2 = (l2_pgentry_t *)alloc_xenheap_page();
+ memset(d->arch.mm_perdomain_l2, 0, PAGE_SIZE);
+ d->arch.mm_perdomain_l2[l2_table_offset(PERDOMAIN_VIRT_START)] =
+ l2e_create_phys(__pa(d->arch.mm_perdomain_pt),
+ __PAGE_HYPERVISOR);
+ d->arch.mm_perdomain_l3 = (l3_pgentry_t *)alloc_xenheap_page();
+ memset(d->arch.mm_perdomain_l3, 0, PAGE_SIZE);
+ d->arch.mm_perdomain_l3[l3_table_offset(PERDOMAIN_VIRT_START)] =
+ l3e_create_phys(__pa(d->arch.mm_perdomain_l2),
__PAGE_HYPERVISOR);
#endif
-
- (void)ptwr_init(d);
-
- shadow_lock_init(d);
- INIT_LIST_HEAD(&d->arch.free_shadow_frames);
- }
+
+ (void)ptwr_init(d);
+
+ shadow_lock_init(d);
+ INIT_LIST_HEAD(&d->arch.free_shadow_frames);
}
void arch_do_boot_vcpu(struct exec_domain *ed)
{
struct domain *d = ed->domain;
+
+ ed->arch.flags = TF_kernel_mode;
+
ed->arch.schedule_tail = d->exec_domain[0]->arch.schedule_tail;
- ed->arch.perdomain_ptes =
+
+ ed->arch.perdomain_ptes =
d->arch.mm_perdomain_pt + (ed->vcpu_id << PDPT_VCPU_SHIFT);
- ed->arch.flags = TF_kernel_mode;
+ ed->arch.perdomain_ptes[FIRST_RESERVED_GDT_PAGE] =
+ l1e_create_pfn(page_to_pfn(virt_to_page(gdt_table)),
+ __PAGE_HYPERVISOR);
}
#ifdef CONFIG_VMX
return -EINVAL;
}
- /* Failure to set GDT is harmless. */
- SET_GDT_ENTRIES(ed, DEFAULT_GDT_ENTRIES);
- SET_GDT_ADDRESS(ed, DEFAULT_GDT_ADDRESS);
- if ( c->gdt_ents != 0 )
+ if ( (rc = (int)set_gdt(ed, c->gdt_frames, c->gdt_ents)) != 0 )
{
- if ( (rc = (int)set_gdt(ed, c->gdt_frames, c->gdt_ents)) != 0 )
- {
- put_page_and_type(&frame_table[phys_basetab>>PAGE_SHIFT]);
- return rc;
- }
+ put_page_and_type(&frame_table[phys_basetab>>PAGE_SHIFT]);
+ return rc;
}
#ifdef CONFIG_VMX
set_bit(cpu, &n->domain->cpuset);
write_ptbase(n);
- __asm__ __volatile__ ( "lgdt %0" : "=m" (*n->arch.gdt) );
+
+ if ( p->vcpu_id != n->vcpu_id )
+ {
+ char gdt_load[10];
+ *(unsigned short *)(&gdt_load[0]) = LAST_RESERVED_GDT_BYTE;
+ *(unsigned long *)(&gdt_load[2]) = GDT_VIRT_START(n);
+ __asm__ __volatile__ ( "lgdt %0" : "=m" (gdt_load) );
+ }
if ( p->domain != n->domain )
clear_bit(cpu, &p->domain->cpuset);
mpt_alloc = (vpt_start - dsi.v_start) + alloc_start;
- SET_GDT_ENTRIES(ed, DEFAULT_GDT_ENTRIES);
- SET_GDT_ADDRESS(ed, DEFAULT_GDT_ADDRESS);
-
/*
* We're basically forcing default RPLs to 1, so that our "what privilege
* level are we returning to?" logic works.
int i;
unsigned long pfn;
- for ( i = 0; i < 16; i++ )
+ ed->arch.guest_context.gdt_ents = 0;
+ for ( i = 0; i < FIRST_RESERVED_GDT_PAGE; i++ )
{
if ( (pfn = l1e_get_pfn(ed->arch.perdomain_ptes[i])) != 0 )
put_page_and_type(&frame_table[pfn]);
ed->arch.perdomain_ptes[i] = l1e_empty();
+ ed->arch.guest_context.gdt_frames[i] = 0;
}
}
{
struct domain *d = ed->domain;
/* NB. There are 512 8-byte entries per GDT page. */
- int i = 0, nr_pages = (entries + 511) / 512;
- struct desc_struct *vgdt;
+ int i, nr_pages = (entries + 511) / 512;
unsigned long pfn;
- /* Check the first page in the new GDT. */
- if ( (pfn = frames[0]) >= max_page )
- goto fail;
-
+ if ( entries > FIRST_RESERVED_GDT_ENTRY )
+ return -EINVAL;
+
shadow_sync_all(d);
- /* The first page is special because Xen owns a range of entries in it. */
- if ( !get_page_and_type(&frame_table[pfn], d, PGT_gdt_page) )
- {
- /* GDT checks failed: try zapping the Xen reserved entries. */
- if ( !get_page_and_type(&frame_table[pfn], d, PGT_writable_page) )
- goto fail;
- vgdt = map_domain_mem(pfn << PAGE_SHIFT);
- memset(vgdt + FIRST_RESERVED_GDT_ENTRY, 0,
- NR_RESERVED_GDT_ENTRIES*8);
- unmap_domain_mem(vgdt);
- put_page_and_type(&frame_table[pfn]);
-
- /* Okay, we zapped the entries. Now try the GDT checks again. */
- if ( !get_page_and_type(&frame_table[pfn], d, PGT_gdt_page) )
- goto fail;
- }
-
- /* Check the remaining pages in the new GDT. */
- for ( i = 1; i < nr_pages; i++ )
+ /* Check the pages in the new GDT. */
+ for ( i = 0; i < nr_pages; i++ )
if ( ((pfn = frames[i]) >= max_page) ||
!get_page_and_type(&frame_table[pfn], d, PGT_gdt_page) )
goto fail;
- /* Copy reserved GDT entries to the new GDT. */
- vgdt = map_domain_mem(frames[0] << PAGE_SHIFT);
- memcpy(vgdt + FIRST_RESERVED_GDT_ENTRY,
- gdt_table + FIRST_RESERVED_GDT_ENTRY,
- NR_RESERVED_GDT_ENTRIES*8);
- unmap_domain_mem(vgdt);
-
/* Tear down the old GDT. */
destroy_gdt(ed);
/* Install the new GDT. */
+ ed->arch.guest_context.gdt_ents = entries;
for ( i = 0; i < nr_pages; i++ )
+ {
+ ed->arch.guest_context.gdt_frames[i] = frames[i];
ed->arch.perdomain_ptes[i] =
l1e_create_pfn(frames[i], __PAGE_HYPERVISOR);
-
- SET_GDT_ADDRESS(ed, GDT_VIRT_START(ed));
- SET_GDT_ENTRIES(ed, entries);
+ }
return 0;
unsigned long frames[16];
long ret;
- if ( (entries <= LAST_RESERVED_GDT_ENTRY) || (entries > 8192) )
- return -EINVAL;
-
if ( copy_from_user(frames, frame_list, nr_pages * sizeof(unsigned long)) )
return -EFAULT;
LOCK_BIGLOCK(current->domain);
if ( (ret = set_gdt(current, frames, entries)) == 0 )
- {
local_flush_tlb();
- __asm__ __volatile__ ("lgdt %0" : "=m" (*current->arch.gdt));
- }
UNLOCK_BIGLOCK(current->domain);
unsigned long mfn;
struct desc_struct *gdt_pent, d;
struct pfn_info *page;
- struct exec_domain *ed;
long ret = -EINVAL;
*(u64 *)&d = desc;
switch ( page->u.inuse.type_info & PGT_type_mask )
{
case PGT_gdt_page:
- /* Disallow updates of Xen-reserved descriptors in the current GDT. */
- for_each_exec_domain(dom, ed) {
- if ( (l1e_get_pfn(ed->arch.perdomain_ptes[0]) == mfn) &&
- (((pa&(PAGE_SIZE-1))>>3) >= FIRST_RESERVED_GDT_ENTRY) &&
- (((pa&(PAGE_SIZE-1))>>3) <= LAST_RESERVED_GDT_ENTRY) )
- goto out;
- }
if ( unlikely(!get_page_type(page, PGT_gdt_page)) )
goto out;
break;
{
int nr = smp_processor_id();
struct tss_struct *t = &init_tss[nr];
+ char gdt_load[10];
if ( test_and_set_bit(nr, &cpu_initialized) )
panic("CPU#%d already initialized!!!\n", nr);
printk("Initializing CPU#%d\n", nr);
- SET_GDT_ENTRIES(current, DEFAULT_GDT_ENTRIES);
- SET_GDT_ADDRESS(current, DEFAULT_GDT_ADDRESS);
- __asm__ __volatile__ ( "lgdt %0" : "=m" (*current->arch.gdt) );
+ *(unsigned short *)(&gdt_load[0]) = LAST_RESERVED_GDT_BYTE;
+ *(unsigned long *)(&gdt_load[2]) = GDT_VIRT_START(current);
+ __asm__ __volatile__ ( "lgdt %0" : "=m" (gdt_load) );
/* No nested task. */
__asm__ __volatile__ ( "pushf ; andw $0xbfff,(%"__OP"sp) ; popf" );
sort_exception_tables();
arch_do_createdomain(current);
-
- identify_cpu(&boot_cpu_data); /* get CPU type info */
- if ( cpu_has_fxsr ) set_in_cr4(X86_CR4_OSFXSR);
- if ( cpu_has_xmm ) set_in_cr4(X86_CR4_OSXMMEXCPT);
+
+ /* Map default GDT into their final position in the idle page table. */
+ map_pages(
+ idle_pg_table,
+ GDT_VIRT_START(current) + FIRST_RESERVED_GDT_BYTE,
+ virt_to_phys(gdt_table), PAGE_SIZE, __PAGE_HYPERVISOR);
+
+ /* Process CPU type information. */
+ identify_cpu(&boot_cpu_data);
+ if ( cpu_has_fxsr )
+ set_in_cr4(X86_CR4_OSFXSR);
+ if ( cpu_has_xmm )
+ set_in_cr4(X86_CR4_OSXMMEXCPT);
find_smp_config();
#include <xen/config.h>
#include <public/xen.h>
+#include <asm/desc.h>
#include <asm/page.h>
#ifdef CONFIG_SMP
.word 0, 0 # idt base = 0L
gdt_48:
- .word (LAST_RESERVED_GDT_ENTRY*8)+7
+ .word LAST_RESERVED_GDT_BYTE
#ifdef __i386__
- .long gdt_table-__PAGE_OFFSET
+ .long gdt_table - FIRST_RESERVED_GDT_BYTE - __PAGE_OFFSET
#else
- .long 0x100200 # gdt_table
+ .long 0x101000 - FIRST_RESERVED_GDT_BYTE
#endif
ENTRY(trampoline_end)
/* Master table, used by all CPUs on x86/64, and by CPU0 on x86/32.*/
idt_entry_t idt_table[IDT_ENTRIES];
-asmlinkage void divide_error(void);
-asmlinkage void debug(void);
+#define DECLARE_TRAP_HANDLER(_name) \
+asmlinkage void _name(void); \
+asmlinkage int do_ ## _name(struct cpu_user_regs *regs)
+
asmlinkage void nmi(void);
-asmlinkage void int3(void);
-asmlinkage void overflow(void);
-asmlinkage void bounds(void);
-asmlinkage void invalid_op(void);
-asmlinkage void device_not_available(void);
-asmlinkage void coprocessor_segment_overrun(void);
-asmlinkage void invalid_TSS(void);
-asmlinkage void segment_not_present(void);
-asmlinkage void stack_segment(void);
-asmlinkage void general_protection(void);
-asmlinkage void page_fault(void);
-asmlinkage void coprocessor_error(void);
-asmlinkage void simd_coprocessor_error(void);
-asmlinkage void alignment_check(void);
-asmlinkage void spurious_interrupt_bug(void);
-asmlinkage void machine_check(void);
+DECLARE_TRAP_HANDLER(divide_error);
+DECLARE_TRAP_HANDLER(debug);
+DECLARE_TRAP_HANDLER(int3);
+DECLARE_TRAP_HANDLER(overflow);
+DECLARE_TRAP_HANDLER(bounds);
+DECLARE_TRAP_HANDLER(invalid_op);
+DECLARE_TRAP_HANDLER(device_not_available);
+DECLARE_TRAP_HANDLER(coprocessor_segment_overrun);
+DECLARE_TRAP_HANDLER(invalid_TSS);
+DECLARE_TRAP_HANDLER(segment_not_present);
+DECLARE_TRAP_HANDLER(stack_segment);
+DECLARE_TRAP_HANDLER(general_protection);
+DECLARE_TRAP_HANDLER(page_fault);
+DECLARE_TRAP_HANDLER(coprocessor_error);
+DECLARE_TRAP_HANDLER(simd_coprocessor_error);
+DECLARE_TRAP_HANDLER(alignment_check);
+DECLARE_TRAP_HANDLER(spurious_interrupt_bug);
+DECLARE_TRAP_HANDLER(machine_check);
static int debug_stack_lines = 20;
integer_param("debug_stack_lines", debug_stack_lines);
return 0;
}
-asmlinkage void do_machine_check(struct cpu_user_regs *regs)
+asmlinkage int do_machine_check(struct cpu_user_regs *regs)
{
fatal_trap(TRAP_machine_check, regs);
+ return 0;
}
void propagate_page_fault(unsigned long addr, u16 error_code)
ed->arch.guest_cr2 = addr;
}
+static int handle_perdomain_mapping_fault(
+ unsigned long offset, struct cpu_user_regs *regs)
+{
+ extern int map_ldt_shadow_page(unsigned int);
+
+ struct exec_domain *ed = current;
+ struct domain *d = ed->domain;
+ int ret;
+
+ /* Which vcpu's area did we fault in, and is it in the ldt sub-area? */
+ unsigned int is_ldt_area = (offset >> (PDPT_VCPU_VA_SHIFT-1)) & 1;
+ unsigned int vcpu_area = (offset >> PDPT_VCPU_VA_SHIFT);
+
+ /* Should never fault in another vcpu's area. */
+ BUG_ON(vcpu_area != current->vcpu_id);
+
+ /* Byte offset within the gdt/ldt sub-area. */
+ offset &= (1UL << (PDPT_VCPU_VA_SHIFT-1)) - 1UL;
+
+ if ( likely(is_ldt_area) )
+ {
+ /* LDT fault: Copy a mapping from the guest's LDT, if it is valid. */
+ LOCK_BIGLOCK(d);
+ ret = map_ldt_shadow_page(offset >> PAGE_SHIFT);
+ UNLOCK_BIGLOCK(d);
+
+ if ( unlikely(ret == 0) )
+ {
+ /* In hypervisor mode? Leave it to the #PF handler to fix up. */
+ if ( !GUEST_MODE(regs) )
+ return 0;
+ /* In guest mode? Propagate #PF to guest, with adjusted %cr2. */
+ propagate_page_fault(
+ ed->arch.guest_context.ldt_base + offset, regs->error_code);
+ }
+ }
+ else
+ {
+ /* GDT fault: handle the fault as #GP(selector). */
+ regs->error_code = (u16)offset & ~7;
+ (void)do_general_protection(regs);
+ }
+
+ return EXCRET_fault_fixed;
+}
+
asmlinkage int do_page_fault(struct cpu_user_regs *regs)
{
- unsigned long off, addr, fixup;
+ unsigned long addr, fixup;
struct exec_domain *ed = current;
struct domain *d = ed->domain;
- int ret;
__asm__ __volatile__ ("mov %%cr2,%0" : "=r" (addr) : );
((addr < HYPERVISOR_VIRT_START) ||
(shadow_mode_external(d) && GUEST_CONTEXT(ed, regs))) &&
shadow_fault(addr, regs) )
- {
return EXCRET_fault_fixed;
- }
- if ( unlikely(addr >= LDT_VIRT_START(ed)) &&
- (addr < (LDT_VIRT_START(ed) +
- (ed->arch.guest_context.ldt_ents*LDT_ENTRY_SIZE))) )
- {
- /*
- * Copy a mapping from the guest's LDT, if it is valid. Otherwise we
- * send the fault up to the guest OS to be handled.
- */
- extern int map_ldt_shadow_page(unsigned int);
- LOCK_BIGLOCK(d);
- off = addr - LDT_VIRT_START(ed);
- addr = ed->arch.guest_context.ldt_base + off;
- ret = map_ldt_shadow_page(off >> PAGE_SHIFT);
- UNLOCK_BIGLOCK(d);
- if ( likely(ret) )
- return EXCRET_fault_fixed; /* successfully copied the mapping */
- }
+ if ( unlikely(addr >= PERDOMAIN_VIRT_START) &&
+ unlikely(addr < PERDOMAIN_VIRT_END) &&
+ handle_perdomain_mapping_fault(addr - PERDOMAIN_VIRT_START, regs) )
+ return EXCRET_fault_fixed;
if ( !GUEST_MODE(regs) )
goto xen_fault;
void set_tss_desc(unsigned int n, void *addr)
{
_set_tssldt_desc(
- gdt_table + __TSS(n),
+ gdt_table + __TSS(n) - FIRST_RESERVED_GDT_ENTRY,
(unsigned long)addr,
offsetof(struct tss_struct, __cacheline_filler) - 1,
9);
}
else /* gdt */
{
- table = (unsigned long *)GET_GDT_ADDRESS(d);
- if ( idx >= GET_GDT_ENTRIES(d) )
+ table = (unsigned long *)GDT_VIRT_START(d);
+ if ( idx >= d->arch.guest_context.gdt_ents )
goto fail;
}
if ( idx >= d->arch.guest_context.ldt_ents )
{
DPRINTK("Segment %04x out of LDT range (%ld)\n",
- seg, d->arch.ldt_ents);
+ seg, d->arch.guest_context.ldt_ents);
goto fail;
}
}
else /* gdt */
{
- table = (unsigned long *)GET_GDT_ADDRESS(d);
- if ( idx >= GET_GDT_ENTRIES(d) )
+ table = (unsigned long *)GDT_VIRT_START(d);
+ if ( idx >= d->arch.guest_context.gdt_ents )
{
- DPRINTK("Segment %04x out of GDT range (%d)\n",
- seg, GET_GDT_ENTRIES(d));
+ DPRINTK("Segment %04x out of GDT range (%ld)\n",
+ seg, d->arch.guest_context.gdt_ents);
goto fail;
}
}
tss->eip = (unsigned long)do_double_fault;
tss->eflags = 2;
tss->bitmap = IOBMP_INVALID_OFFSET;
- _set_tssldt_desc(gdt_table+__DOUBLEFAULT_TSS_ENTRY,
- (unsigned long)tss, 235, 9);
+ _set_tssldt_desc(
+ gdt_table + __DOUBLEFAULT_TSS_ENTRY - FIRST_RESERVED_GDT_ENTRY,
+ (unsigned long)tss, 235, 9);
set_task_gate(TRAP_double_fault, __DOUBLEFAULT_TSS_ENTRY<<3);
}
#define OPT_CONSOLE_STR "com1,vga"
-/*
- * If you increase this value, please update NR_RESERVED_GDT_ENTRIES
- * in include/public/arch-x86_xx.h
- */
#define NR_CPUS 32
/* Linkage for x86 */
#define PGT_base_page_table PGT_l4_page_table
-#define __HYPERVISOR_CS64 0x0810
-#define __HYPERVISOR_CS32 0x0808
+#define __HYPERVISOR_CS64 0xe010
+#define __HYPERVISOR_CS32 0xe008
#define __HYPERVISOR_CS __HYPERVISOR_CS64
#define __HYPERVISOR_DS64 0x0000
-#define __HYPERVISOR_DS32 0x0818
+#define __HYPERVISOR_DS32 0xe018
#define __HYPERVISOR_DS __HYPERVISOR_DS64
-#define __GUEST_CS64 0x0833
-#define __GUEST_CS32 0x0823
+#define __GUEST_CS64 0xe033
+#define __GUEST_CS32 0xe023
#define __GUEST_CS __GUEST_CS64
#define __GUEST_DS 0x0000
-#define __GUEST_SS 0x082b
+#define __GUEST_SS 0xe02b
/* For generic assembly code: use macros to define operation/operand sizes. */
#define __OS "q" /* Operation Suffix */
#define PGT_base_page_table PGT_l2_page_table
-#define __HYPERVISOR_CS 0x0808
-#define __HYPERVISOR_DS 0x0810
+#define __HYPERVISOR_CS 0xe008
+#define __HYPERVISOR_DS 0xe010
/* For generic assembly code: use macros to define operation/operand sizes. */
#define __OS "l" /* Operation Suffix */
extern unsigned long xenheap_phys_end; /* user-configurable */
#endif
-#define GDT_VIRT_START(ed) (PERDOMAIN_VIRT_START + ((ed)->vcpu_id << PDPT_VCPU_VA_SHIFT))
-#define GDT_VIRT_END(ed) (GDT_VIRT_START(ed) + (64*1024))
-#define LDT_VIRT_START(ed) (PERDOMAIN_VIRT_START + (64*1024) + ((ed)->vcpu_id << PDPT_VCPU_VA_SHIFT))
-#define LDT_VIRT_END(ed) (LDT_VIRT_START(ed) + (64*1024))
+#define GDT_VIRT_START(ed) \
+ (PERDOMAIN_VIRT_START + ((ed)->vcpu_id << PDPT_VCPU_VA_SHIFT))
+#define LDT_VIRT_START(ed) \
+ (GDT_VIRT_START(ed) + (64*1024))
#define PDPT_VCPU_SHIFT 5
#define PDPT_VCPU_VA_SHIFT (PDPT_VCPU_SHIFT + PAGE_SHIFT)
#ifndef __ARCH_DESC_H
#define __ARCH_DESC_H
-#ifndef __ASSEMBLY__
+
+/*
+ * Xen reserves a memory page of GDT entries.
+ * No guest GDT entries exist beyond the Xen reserved area.
+ */
+#define NR_RESERVED_GDT_PAGES 1
+#define NR_RESERVED_GDT_BYTES (NR_RESERVED_GDT_PAGES * PAGE_SIZE)
+#define NR_RESERVED_GDT_ENTRIES (NR_RESERVED_GDT_BYTES / 8)
+
+#define LAST_RESERVED_GDT_PAGE \
+ (FIRST_RESERVED_GDT_PAGE + NR_RESERVED_GDT_PAGES - 1)
+#define LAST_RESERVED_GDT_BYTE \
+ (FIRST_RESERVED_GDT_BYTE + NR_RESERVED_GDT_BYTES - 1)
+#define LAST_RESERVED_GDT_ENTRY \
+ (FIRST_RESERVED_GDT_ENTRY + NR_RESERVED_GDT_ENTRIES - 1)
#define LDT_ENTRY_SIZE 8
* is ignored when the gate is accessed.
*/
#define VALID_SEL(_s) \
- (((((_s)>>3) < FIRST_RESERVED_GDT_ENTRY) || \
- (((_s)>>3) > LAST_RESERVED_GDT_ENTRY) || \
- ((_s)&4)) && \
+ (((((_s)>>3) < FIRST_RESERVED_GDT_ENTRY) || ((_s)&4)) && \
(((_s)&3) == GUEST_KERNEL_RPL))
#define VALID_CODESEL(_s) ((_s) == FLAT_KERNEL_CS || VALID_SEL(_s))
#define _SEGMENT_DB ( 1<<22) /* 16- or 32-bit segment */
#define _SEGMENT_G ( 1<<23) /* Granularity */
+#ifndef __ASSEMBLY__
+
struct desc_struct {
u32 a, b;
};
extern void set_tss_desc(unsigned int n, void *addr);
#endif /* !__ASSEMBLY__ */
+
#endif /* __ARCH_DESC_H */
/* Current LDT details. */
unsigned long shadow_ldt_mapcnt;
- /* Next entry is passed to LGDT on domain switch. */
- char gdt[10]; /* NB. 10 bytes needed for x86_64. Use 6 bytes for x86_32. */
} __cacheline_aligned;
#define IDLE0_ARCH_EXEC_DOMAIN \
else
{
cpu = smp_processor_id();
- desc = (struct desc_struct *)GET_GDT_ADDRESS(ed) + __LDT(cpu);
+ desc = gdt_table + __LDT(cpu) - FIRST_RESERVED_GDT_ENTRY;
desc->a = ((LDT_VIRT_START(ed)&0xffff)<<16) | (ents*8-1);
desc->b = (LDT_VIRT_START(ed)&(0xff<<24)) | 0x8200 |
((LDT_VIRT_START(ed)&0xff0000)>>16);
}
#define set_machinetophys(_mfn, _pfn) machine_to_phys_mapping[(_mfn)] = (_pfn)
-#define DEFAULT_GDT_ENTRIES (LAST_RESERVED_GDT_ENTRY+1)
-#define DEFAULT_GDT_ADDRESS ((unsigned long)gdt_table)
-
#ifdef MEMORY_GUARD
void *memguard_init(void *heap_start);
void memguard_guard_stack(void *p);
extern void write_ptbase(struct exec_domain *ed);
-#define SET_GDT_ENTRIES(_p, _e) \
- ((*(u16 *)((_p)->arch.gdt + 0)) = (((_e)<<3)-1))
-#define SET_GDT_ADDRESS(_p, _a) \
- ((*(unsigned long *)((_p)->arch.gdt + 2)) = (_a))
-#define GET_GDT_ENTRIES(_p) \
- (((*(u16 *)((_p)->arch.gdt + 0))+1)>>3)
-#define GET_GDT_ADDRESS(_p) \
- (*(unsigned long *)((_p)->arch.gdt + 2))
-
void destroy_gdt(struct exec_domain *d);
long set_gdt(struct exec_domain *d,
unsigned long *frames,
+++ /dev/null
-#ifndef __ARCH_LDT_H
-#define __ARCH_LDT_H
-
-#ifndef __ASSEMBLY__
-
-static inline void load_LDT(struct domain *p)
-{
- unsigned long ents;
-
- if ( (ents = p->mm.ldt_ents) == 0 )
- {
- __asm__ __volatile__ ( "lldt %w0" : : "r" (0) );
- }
- else
- {
- unsigned int cpu;
- struct ldttss_desc *desc;
-
- cpu = smp_processor_id();
- desc = (struct ldttss_desc *)((char *)GET_GDT_ADDRESS(p) + __CPU_DESC_INDEX(cpu, ldt));
- desc->limit0 = ents*8-1;
- desc->base0 = LDT_VIRT_START&0xffff;
- desc->base1 = (LDT_VIRT_START&0xff0000)>>16;
- desc->type = DESC_LDT;
- desc->dpl = 0;
- desc->p = 1;
- desc->limit1 = 0;
- desc->zero0 = 0;
- desc->g = 0;
- desc->base2 = (LDT_VIRT_START&0xff000000)>>24;
- desc->base3 = LDT_VIRT_START>>32;
- desc->zero1 = 0;
- __load_LDT(cpu);
- }
-}
-
-#endif /* !__ASSEMBLY__ */
-
-#endif
* A number of GDT entries are reserved by Xen. These are not situated at the
* start of the GDT because some stupid OSes export hard-coded selector values
* in their ABI. These hard-coded values are always near the start of the GDT,
- * so Xen places itself out of the way.
- *
- * NR_RESERVED_GDT_ENTRIES is (8 + 2 * NR_CPUS) Please update this value if
- * you increase NR_CPUS or add another GDT entry to gdt_table in x86_32.S
- *
- * NB. The reserved range is inclusive (that is, both FIRST_RESERVED_GDT_ENTRY
- * and LAST_RESERVED_GDT_ENTRY are reserved).
+ * so Xen places itself out of the way, at the far end of the GDT.
*/
-#define NR_RESERVED_GDT_ENTRIES 72
-#define FIRST_RESERVED_GDT_ENTRY 256
-#define LAST_RESERVED_GDT_ENTRY \
- (FIRST_RESERVED_GDT_ENTRY + NR_RESERVED_GDT_ENTRIES - 1)
-
+#define FIRST_RESERVED_GDT_PAGE 14
+#define FIRST_RESERVED_GDT_BYTE (FIRST_RESERVED_GDT_PAGE * 4096)
+#define FIRST_RESERVED_GDT_ENTRY (FIRST_RESERVED_GDT_BYTE / 8)
/*
* These flat segments are in the Xen-private section of every GDT. Since these
* are also present in the initial GDT, many OSes will be able to avoid
* installing their own GDT.
*/
-#define FLAT_RING1_CS 0x0819 /* GDT index 259 */
-#define FLAT_RING1_DS 0x0821 /* GDT index 260 */
-#define FLAT_RING1_SS 0x0821 /* GDT index 260 */
-#define FLAT_RING3_CS 0x082b /* GDT index 261 */
-#define FLAT_RING3_DS 0x0833 /* GDT index 262 */
-#define FLAT_RING3_SS 0x0833 /* GDT index 262 */
+#define FLAT_RING1_CS 0xe019 /* GDT index 259 */
+#define FLAT_RING1_DS 0xe021 /* GDT index 260 */
+#define FLAT_RING1_SS 0xe021 /* GDT index 260 */
+#define FLAT_RING3_CS 0xe02b /* GDT index 261 */
+#define FLAT_RING3_DS 0xe033 /* GDT index 262 */
+#define FLAT_RING3_SS 0xe033 /* GDT index 262 */
#define FLAT_KERNEL_CS FLAT_RING1_CS
#define FLAT_KERNEL_DS FLAT_RING1_DS
* A number of GDT entries are reserved by Xen. These are not situated at the
* start of the GDT because some stupid OSes export hard-coded selector values
* in their ABI. These hard-coded values are always near the start of the GDT,
- * so Xen places itself out of the way.
- *
- * NR_RESERVED_GDT_ENTRIES is (8 + 4 * NR_CPUS) Please update this value if
- * you increase NR_CPUS or add another GDT entry to gdt_table in boot/x86_64.S
- *
- * NB. The reserved range is inclusive (that is, both FIRST_RESERVED_GDT_ENTRY
- * and LAST_RESERVED_GDT_ENTRY are reserved).
+ * so Xen places itself out of the way, at the far end of the GDT.
*/
-#define NR_RESERVED_GDT_ENTRIES 136
-#define FIRST_RESERVED_GDT_ENTRY 256
-#define LAST_RESERVED_GDT_ENTRY \
- (FIRST_RESERVED_GDT_ENTRY + NR_RESERVED_GDT_ENTRIES - 1)
+#define FIRST_RESERVED_GDT_PAGE 14
+#define FIRST_RESERVED_GDT_BYTE (FIRST_RESERVED_GDT_PAGE * 4096)
+#define FIRST_RESERVED_GDT_ENTRY (FIRST_RESERVED_GDT_BYTE / 8)
/*
* 64-bit segment selectors
* installing their own GDT.
*/
-#define FLAT_RING3_CS32 0x0823 /* GDT index 260 */
-#define FLAT_RING3_CS64 0x0833 /* GDT index 261 */
-#define FLAT_RING3_DS32 0x082b /* GDT index 262 */
+#define FLAT_RING3_CS32 0xe023 /* GDT index 260 */
+#define FLAT_RING3_CS64 0xe033 /* GDT index 261 */
+#define FLAT_RING3_DS32 0xe02b /* GDT index 262 */
#define FLAT_RING3_DS64 0x0000 /* NULL selector */
-#define FLAT_RING3_SS32 0x082b /* GDT index 262 */
-#define FLAT_RING3_SS64 0x082b /* GDT index 262 */
+#define FLAT_RING3_SS32 0xe02b /* GDT index 262 */
+#define FLAT_RING3_SS64 0xe02b /* GDT index 262 */
#define FLAT_KERNEL_DS64 FLAT_RING3_DS64
#define FLAT_KERNEL_DS32 FLAT_RING3_DS32